<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
  <head>
    <title>Railroad</title>
    <!-- First, we load the supporting JS library. -->
    <script src="../src/railroad.js"></script>
    <!-- We can style railroad nodes however we like.  The names "terminal" and "nonterminal" are conventions used by this file, and not restrictions imposed by the underlying library. -->
    <style>
    .terminal { border: 1px solid black; border-radius: 6px; padding: 2px; background: #efe; display: inline-block; text-align: center }
    .nonterminal { border: 1px solid black; padding: 2px; background: #efe; display: inline-block }
    </style>
  </head>

  <body>
    <h1>Railroad</h1>
    <p>The JSON grammar as described at <a href="http://json.org/">json.org</a> except that the railroad diagrams are generated by JavaScript.
    <p>Check out the HTML source of this file.  The styling of the nodes is entirely done in CSS, nodes can contain arbitrary HTML (though position:fixed might behave strangely), and grammars are declared using declarative-style JS function calls at the bottom of this file.  This should work on any browser that supports CSS3 the <code>border-bottom-right-radius</code> property et al. for doing rounded corners -- no SVG required.
    <hr>

    <!-- Next, we give the grammars a place to live.  The *-railroad DIVs will contain the railroad diagram, though that convention is defined by this file, not by the underlying library. -->

    <p>An object is an unordered set of name/value pairs.
    <div id="object-railroad"></div>

    <p>An array is an ordered collection of values.
    <div id="array-railroad"></div>

    <p>A value can be a string in double quotes, a number, a keyword value, an object, or an array.
    <div id="value-railroad"></div>

    <p>A string is a sequence of zero or more UTF-16 Unicode code units.
    <div id="string-railroad"></div>

    <p>A number is very much like a C or Java number, except that the octal and hexadecimal formats are not used, and there is no letter suffix to specify size or signedness.
    <div id="number-railroad"></div>

    <p>Whitespace can be inserted between any pair of tokens outside strings.  Excepting a few encoding details, that completely describes the language.

   <!-- Finally, we include a script that defines our grammars. -->
   <script>(function () {
// Import the grammar definition functions from railroad.js
var any = railroad.any,      // Like * in EBNF (0 or more repetitions)
    each = railroad.each,    // each(a, b, c)  produces (A -> B -> C)
    many = railroad.many,    // Like + in EBNF (1 or more repetitions)
    maybe = railroad.maybe,  // Like ? in EBNF (0 or 1 occurences)
    or = railroad.or;        // Like | in EBNF (choose 1 of)

// Define some helper functions that format things the way we like.
/** Plain text to HTML. */
function html(str) {
  return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
      .replace(/\u0022/g, '&quot;').replace(/\u0027/g, '&#39;');
}

/** Produces HTML for a literal sequence of characters. */
function terminal(str) {
  return '<span class=terminal>`<kbd>' + html(str) + '<\/kbd>`<\/span>';
}

/** Generate a reference to another production, possibly linking to it. */
function nonTerminal(name) {
  if (document.getElementById(name + '-railroad')) {
    return '<span class=nonterminal><a href="#' + html(name) + '-railroad">' + html(name) + '<\/a><\/span>';
  } else {
    return '<span class=nonterminal>' + html(name) + '<\/span>';
  }
}

/** Fills in one of the <div id=*-railroad> above. */
function grammar(name, root) {
  var stats = {};
  var railroadContainer = document.getElementById(name + '-railroad');
  railroad.appendToDOM(root, railroadContainer, stats);
  railroadContainer.style.width = stats.width + 'px';
  railroadContainer.style.height = stats.height + 'px';
}


// Use a declarative syntax to define the grammar.
grammar('object',
    each(
        terminal('{'),
        any(
            each(nonTerminal('string'), terminal(':'), nonTerminal('value')),
            terminal(',')),
        terminal('}')));

grammar('array',
    each(
        terminal('['),
        any(
            nonTerminal('value'),
            terminal(',')),
        terminal(']')));

grammar('value',
    or(
        nonTerminal('string'),
        nonTerminal('number'),
        nonTerminal('object'),
        nonTerminal('array'),
        terminal('true'),
        terminal('false'),
        terminal('null')));

grammar('string',
    each(
        terminal('\u0022'),
        any(
            or(
                '<span class=terminal><i>Any&nbsp;UNICODE&nbsp;code&nbsp;unit&nbsp;except<br>`<kbd>&quot;</kbd>`,&nbsp;<kbd>`\\`</kbd>,&nbsp;or&nbsp;a&nbsp;control&nbsp;character</i></span>',
                each(
                    terminal('\\'),
                    or(
                         terminal('\u0022', 'quotation mark'),
                         terminal('\\', 'reverse solidus'),
                         terminal('/', 'solidus'),
                         terminal('b', 'backspace'),
                         terminal('f', 'backspace'),
                         terminal('n', 'backspace'),
                         terminal('r', 'backspace'),
                         terminal('t', 'backspace'),
                         each(terminal('u'), '<span class=terminal>4&nbsp;hexadecimal<br>digits<\/span>'))))),
        terminal('\u0022')));

var digit = '<span class=terminal>digit</span>';
grammar('number',
    each(
        maybe(terminal('-')),
        or(
            terminal('0'),
            each('<span class=terminal>digit<br>1-9</span>', any(digit))),
        maybe(
            each(terminal('.'), any(digit))),
        maybe(
            each(
                or(terminal('e'), terminal('E')),
                maybe(or(terminal('+'), terminal('-'))),
                many(digit)))));
   })();</script>
  </body>
</html>
